package fr.jade.fraclite.deployment;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.Type;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.fractal.api.factory.GenericFactory;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.api.type.TypeFactory;
import org.objectweb.fractal.deployment.local.api.IPhysicalPackageRepository;
import org.objectweb.fractal.util.Fractal;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import fr.jade.fraclite.FracLite;

public class BasicPhysicalPackageRepository implements
		IPhysicalPackageRepository, BindingController, LifeCycleController {

	Map<String, Component> packageBase = new HashMap<String, Component>();

	TypeFactory tf = null;

	GenericFactory gf = null;

	boolean started = false;

	Component thisComponent = null;

	Component bootstrapComposite = null;

	public String[] listFc() {
		return new String[] { "gf", "tf" };
	}

	public Object lookupFc(String arg0) throws NoSuchInterfaceException {
		if (arg0.equals("gf")) {
			return this.gf;
		} else if (arg0.equals("tf")) {
			return this.tf;
		}
		return null;
	}

	public void bindFc(String arg0, Object arg1)
			throws NoSuchInterfaceException, IllegalBindingException,
			IllegalLifeCycleException {
		if (arg0.equals("gf")) {
			this.gf = (GenericFactory) arg1;
		} else if (arg0.equals("tf")) {
			this.tf = (TypeFactory) arg1;
		} else if (arg0.equals("component")) {
			this.thisComponent = (Component) arg1;
		}
	}

	public void unbindFc(String arg0) throws NoSuchInterfaceException,
			IllegalBindingException, IllegalLifeCycleException {
		if (arg0.equals("gf")) {
			this.gf = null;
		} else if (arg0.equals("tf")) {
			this.tf = null;
		}
	}

	public String getFcState() {
		if (started) {
			return LifeCycleController.STARTED;
		} else {
			return LifeCycleController.STOPPED;
		}
	}

	public void startFc() throws IllegalLifeCycleException {
		if (started) {
			return;
		}

		Component[] parents;
		try {
			parents = Fractal.getSuperController(thisComponent)
					.getFcSuperComponents();
			for (int i = 0; i < parents.length; i++) {
				String name = Fractal.getNameController(parents[i]).getFcName();
				if (name.equals("bootstrapComposite")) {
					bootstrapComposite = parents[i];
				}
			}
		} catch (NoSuchInterfaceException e1) {
			e1.printStackTrace();
		}

		String configFileName = System.getProperty("repository.config");

		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder db = factory.newDocumentBuilder();

			InputStream configIS = null;
			if (configFileName != null) {
				// look for the user-specified FracLite configuration file in
				// the file system
				configIS = new FileInputStream(new File(configFileName));

				if (configIS == null) {
					// look for the user-specified FracLite configuration file
					// in
					// the class path
					configIS = getClass().getResourceAsStream(configFileName);
				}
			}

			if (configIS == null) {
				// look for the default FracLite configuration file in the
				// class path
				configIS = getClass().getClassLoader().getResourceAsStream(
						FracLite.DEFAULT_MODULE_REPOSITORY_FILE_NAME);
			}

			Document doc = db.parse(configIS);

			NodeList modules = doc.getElementsByTagName("module");
			for (int i = 0; i < modules.getLength(); i++) {

				Element moduleDescNode = (Element) modules.item(i);
				NodeList nodes = moduleDescNode.getElementsByTagName("content");

				for (int j = 0; j < nodes.getLength(); j++) {
					Element moduleCont = (Element) moduleDescNode
							.getElementsByTagName("content").item(j);
					if (moduleCont != null) {
						String packageContent = moduleCont.getAttribute("file");
						if (packageContent != null
								&& !packageBase.containsKey(packageContent)) {
							InterfaceType pkgItfType = tf
									.createFcItfType(
											"physicalPackage",
											"org.objectweb.fractal.deployment.local.api.IPhysicalPackage",
											false, false, false);
							InterfaceType ncItfType = tf
							.createFcItfType(
									"name-controller",
									"org.objectweb.fractal.api.control.NameController",
									false, false, false);
							Type componentType = tf
									.createFcType(new InterfaceType[] { ncItfType, pkgItfType });
							Component packageComponent = gf
									.newFcInstance(componentType, "physicalPackage",
											"fr.jade.fraclite.deployment.GenericPhysicalPackageComponent");

							Fractal.getNameController(packageComponent)
									.setFcName(packageContent);

							Fractal.getContentController(bootstrapComposite)
									.addFcSubComponent(packageComponent);
							
							packageBase.put(packageContent, packageComponent);
						}
					}

				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		started = true;
	}

	public void stopFc() throws IllegalLifeCycleException {
		if (!started) {
			return;
		} else {
			started = false;
		}
	}

	public Component getPackage(Object pkgDesc) {
		if (pkgDesc instanceof String) {
			return packageBase.get(pkgDesc);
		}
		return null;
	}

}
